﻿#region License
/* **********************************************************************************
 * Copyright (c) Roman Ivantsov
 * This source code is subject to terms and conditions of the MIT License
 * for Irony. A copy of the license can be found in the License.txt file
 * at the root of this distribution. 
 * By using this source code in any fashion, you are agreeing to be bound by the terms of the 
 * MIT License.
 * You must not remove this notice from this software.
 * **********************************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Irony.Parsing.Construction;

namespace Irony.Parsing
{

    /// <summary> A hint to use precedence. </summary>
    /// <remarks>
    /// Not used directly in grammars; injected automatically by system in states having conflicts on operator symbols. 
    /// The purpose of the hint is make handling precedence similar to other conflict resolution methods - through hints
    /// activated during parser construction. The hint code analyzes the conflict and resolves it by adding custom or general action
    /// for a conflicting input. 
    /// </remarks>
    public class PrecedenceHint : GrammarHint
    {

        public override void Apply(LanguageData language, LRItem owner)
        {
            var state = owner.State;
            var allConflicts = state.BuilderData.Conflicts;
            if (allConflicts.Count == 0)
                return;
            //Find all conflicts that can be resolved by operator precedence
            // SL does not support Find extension, so we do it with explicit loop
            var operConflicts = new List<Terminal>();
            foreach (var c in allConflicts)
                if (c.Flags.IsSet(TermFlags.IsOperator))
                    operConflicts.Add(c);
            foreach (var conflict in operConflicts)
            {
                var newState = state.BuilderData.GetNextState(conflict);
                var reduceItem = state.BuilderData.ReduceItems.SelectByLookahead(conflict).First(); //should be only one
                state.Actions[conflict] = new PrecedenceBasedParserAction(conflict, newState, reduceItem.Core.Production);
                allConflicts.Remove(conflict);
            }//foreach conflict
        }

    }//class



}//namespace
